﻿using ZeroBug.EasyFlow.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;

namespace ZeroBug.EasyFlow.Motion
{
    [Serializable]
    public class Cylinder : IMachineResource<IDigitalIO>, IResourceVariable
    {
        [XmlIgnore]
        public IDigitalIO DigitalOperator1 { get; set; }
        [XmlIgnore]
        public IDigitalIO DigitalOperator2 { get; set; }
        public short BitNo1 { get; set; }
        public short BitNo2 { get; set; } = -1;
        public short CardNo { get; set; }
        public string Description { get; set; }
        public string Module { get; set; }
        public string ID1 { get; set; }
        public string ID2 { get; set; }
        private List<Sensor> _moves;
        [XmlIgnore]
        public List<Sensor> Moves
        {
            get { return _moves; }
            set
            {
                _moves = value;
                if (this._moves != null)
                {
                    if (MoveNames == null)
                        MoveNames = new List<string>();
                    foreach (Sensor s in this._moves)
                    {
                        MoveNames.Add(s.Description);
                    }
                }
            }
        }
        private List<Sensor> _origins;
        [XmlIgnore]
        public List<Sensor> Origins
        {
            get { return _origins; }
            set
            {
                _origins = value;
                if (this._origins != null)
                {
                    if (OriginNames == null)
                        OriginNames = new List<string>();
                    foreach (Sensor s in this._origins)
                    {
                        OriginNames.Add(s.Description);
                    }
                }
            }
        }
        [TextVariable]
        public List<string> MoveNames { get; set; }
        public List<string> OriginNames { get; set; }
        public SerializableDictionary<string, string> CsvName2Property { get; set; }
        [XmlIgnore]
        public Func<(bool,string)> PreCheckOn { get; set; }
        [XmlIgnore]
        public Func<(bool, string)> PreCheckOff { get; set; }
        public string OperatorName { get; set; }
        [XmlIgnore]
        public LogHelper Logger { get; set; }
        public Cylinder()
        {
            MoveNames = new List<string>();
            OriginNames = new List<string>();
            Moves = new List<Sensor>();
            Origins = new List<Sensor>();
            CsvName2Property = new SerializableDictionary<string, string>();
            CsvName2Property.Add("名称", nameof(Description));
            CsvName2Property.Add("所属模组", nameof(Module));
            CsvName2Property.Add("所属轴卡号", nameof(CardNo));
            CsvName2Property.Add("点位号1", nameof(BitNo1));
            CsvName2Property.Add("点位号2", nameof(BitNo2));
            CsvName2Property.Add("ID1", nameof(ID1));
            CsvName2Property.Add("ID2", nameof(ID2));
        }
        public Cylinder(string name)
            : this()
        {
            this.Description = name;
        }
        public Cylinder(string name, short cardNo, short bitNo1, string id1, string moduleName, 
                        short bitNo2 = -1, string id2 = "",
                        List<Sensor> move = null, List<Sensor> origin = null)
            : this(name)
        {
            this.CardNo = cardNo;
            this.BitNo1 = bitNo1;
            this.BitNo2 = bitNo2;
            this.ID1 = id1;
            this.ID2 = id2;
            this.Moves = move;
            this.Origins = origin;
            this.Module = moduleName;
            if (this.Moves != null)
            {
                if (MoveNames == null)
                    MoveNames = new List<string>();
                foreach (Sensor s in this.Moves)
                {
                    MoveNames.Add(s.Description);
                }
            }
            if (this.Origins != null)
            {
                if (OriginNames == null)
                    OriginNames = new List<string>();
                foreach (Sensor s in this.Origins)
                {
                    OriginNames.Add(s.Description);
                }
            }
        }
        public (bool,string) On()
        {
            bool result = true;
            string errInfo = "";
            if (PreCheckOn != null)
                (result,errInfo) = PreCheckOn.Invoke();
            if (result)
            {
                if (BitNo2 != -1)
                {
                    DigitalOperator2.ClearOutBitStatus(CardNo, BitNo2);
                    DigitalOperator1.SetOutBitStatus(CardNo, BitNo1);
                }
                else
                    DigitalOperator1.SetOutBitStatus(CardNo, BitNo1);
            }
            return (result, errInfo);
        }
        public (bool, string) Off()
        {
            bool result = true;
            string errInfo = "";
            if (PreCheckOff != null)
                (result, errInfo) = PreCheckOff.Invoke();
            if (result)
            {
                if (BitNo2 != -1)
                {
                    DigitalOperator2.SetOutBitStatus(CardNo, BitNo2);
                    DigitalOperator1.ClearOutBitStatus(CardNo, BitNo1);
                }
                else
                    DigitalOperator1.ClearOutBitStatus(CardNo, BitNo1);
            }
            return (result, errInfo);
        }
        public bool AlreadyOn()
        {
            if (BitNo2 != -1)
                return DigitalOperator1.GetOutBitStatus(CardNo, BitNo1) && !DigitalOperator2.GetOutBitStatus(CardNo, BitNo2);
            return DigitalOperator1.GetOutBitStatus(CardNo, BitNo1);
        }
        public bool AlreadyOff()
        {
            if (BitNo2 != -1)
                return !DigitalOperator1.GetOutBitStatus(CardNo, BitNo1) && DigitalOperator2.GetOutBitStatus(CardNo, BitNo2);
            return !DigitalOperator1.GetOutBitStatus(CardNo, BitNo1);
        }
        public bool WaitOn(int waitTime = 0)
        {
            bool result = true;
            string errInfo = "";
            if (PreCheckOn != null)
                (result, errInfo) = PreCheckOn.Invoke();
            if (result)
                On();
            else
                return false;
            return InMove(waitTime);
        }
        public bool WaitOff(int waitTime = 0)
        {
            bool result = true;
            string errInfo = "";
            if (PreCheckOff != null)
                (result, errInfo) = PreCheckOff.Invoke();
            if (result)
                Off();
            else
                return false;
            return InOrigin(waitTime);
        }
        public bool InMove(int waitTime = 0)
        {
            if (Moves != null)
            {
                bool isInMove = true;
                foreach (Sensor move in Moves)
                {
                    isInMove = move.WaitOn(waitTime) && isInMove;
                    if (!isInMove)
                        break;
                }
                return isInMove;
            }
            else
            {
                if (Origins != null)
                {
                    bool isInMove = true;
                    foreach (Sensor origin in Origins)
                    {
                        isInMove = !origin.WaitOn(waitTime) && isInMove;
                        if (!isInMove)
                            break;
                    }
                    return isInMove;
                }
                else
                    return true;
            }
        }
        public bool InOrigin(int waitTime = 0)
        {
            if (Origins != null)
            {
                bool isInOrigin = true;
                foreach (Sensor origin in Origins)
                {
                    isInOrigin = origin.WaitOn(waitTime) && isInOrigin;
                    if (!isInOrigin)
                        break;
                }
                return isInOrigin;
            }
            else
            {
                if (Moves != null)
                {
                    bool isInOrigin = true;
                    foreach (Sensor move in Moves)
                    {
                        isInOrigin = !move.WaitOn(waitTime) && isInOrigin;
                        if (!isInOrigin)
                            break;
                    }
                    return isInOrigin;
                }
                else
                    return true;
            }
        }
        public void Stop()
        {
            //双控气缸，停止
            if (BitNo2 != -1)
            {
                DigitalOperator2.ClearOutBitStatus(CardNo, BitNo2);
                DigitalOperator1.ClearOutBitStatus(CardNo, BitNo1);
            }
        }

        public void SetOperator(IDigitalIO machineOperator)
        {
            this.DigitalOperator1 = machineOperator;
            this.DigitalOperator2 = machineOperator;
        }
    }
}
